package com.biz.primus.ms.product.service;

import com.biz.primus.base.enums.vendor.VendorType;
import com.biz.primus.base.vo.commodity.ProductIdxIdentityVo;
import com.biz.primus.base.vo.search.ProductIdxVo;
import com.biz.primus.commodity.vo.CommodityVo;
import com.biz.primus.model.promotion.vo.req.SingleProductSpecialOfferPriceReqVo;
import com.biz.primus.ms.product.feign.CommodityFeignClient;
import com.biz.primus.ms.product.feign.DepotFeignClient;
import com.biz.primus.ms.product.feign.PriceFeignClient;
import com.biz.primus.ms.product.feign.StockFeignClient;
import com.biz.primus.ms.product.interfaces.ProductPrototype;
import com.biz.primus.ms.product.interfaces.vo.CommodityCatchVo;
import com.biz.primus.search.vo.search.ProductIdxReqVo;
import com.biz.primus.search.vo.search.ProductIdxRespVo;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.Lists;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.time.StopWatch;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 商品索引ServiceImpl
 *
 * @author david-liu
 * @date 2017年01月19日
 * @reviewer
 */
@Service
public class ProductIdxService extends AbstractProductService {
    private static final long serialVersionUID = 1687087661899158754L;

    private static final Logger logger = LoggerFactory.getLogger(ProductIdxService.class);

    @Autowired
    private CommodityFeignClient productRedisDao;

    @Autowired
    private PriceFeignClient priceRedisDao;

    @Autowired
    private DepotFeignClient depotService;

    @Autowired
    private StockFeignClient productStockService;


    /**
     * key 为vendorType 的value
     * 目前只缓存B类商品
     */
    private LoadingCache<Integer, CommodityCatchVo> typeBproductCache =
            CacheBuilder.newBuilder().initialCapacity(20).expireAfterWrite(10, TimeUnit.MINUTES)
                    .build(new CacheLoader<Integer, CommodityCatchVo>() {
                        @Override
                        public CommodityCatchVo load(Integer key) throws Exception {
                            if (Objects.equals(key, VendorType.TYPE_B.getValue())){
                                List<String> productCodes = Optional.ofNullable(productRedisDao.getTypeProductCodes(VendorType.TYPE_B)).orElse(Lists.<String>newArrayList());
                                List<CommodityVo> productRos = Optional.ofNullable(productRedisDao.findCommoditiesByCodes(productCodes)).orElse(Lists.<CommodityVo>newArrayList());
                                CommodityCatchVo commodityCatchVo = new CommodityCatchVo(productRos,productCodes);
                                return commodityCatchVo;
                            }
                            return new CommodityCatchVo();
                        }
                    });

    /**
     * 刷新商品guava缓存
     * 目前仅给B类商品使用,A类商品没有缓存.
     * 触发B类商品全量索引的时候调用
     */
    public void refershProductCache(){
        StopWatch watch = new StopWatch();
        watch.start();
        logger.info("refersh typeBproduct guava catch");
        typeBproductCache.refresh(VendorType.TYPE_B.getValue());
        watch.stop();
        logger.info("refersh success cost: {} ms",watch.getTime());
    }



    /**
     * 构建商品增量索引
     *
     * @param identityVo 商品增量标识vo
     * @return 商品增量vo
     */
    public ProductIdxVo getSearchIdx(ProductIdxIdentityVo identityVo) {
        if (logger.isDebugEnabled()) {
            logger.debug("getSearchIdx identityVo: {}", identityVo);
        }
        SingleProductSpecialOfferPriceReqVo specialOfferPriceReqVo = new SingleProductSpecialOfferPriceReqVo();
        specialOfferPriceReqVo.setShopId(identityVo.getShopId());
        ProductPrototype productPrototype = this.builder(identityVo.getProductCode())
                .builStock(identityVo.getDepotCode())
                .buildPrice(identityVo.getDepotCode(), specialOfferPriceReqVo)
                .build();
        return productPrototype == null ? null : productPrototype.toProductIdx(identityVo.getDepotCode());
    }

    /**
     * 批量构建商品增量索引(仅提供给B类商品用)
     *
     * @param identityVos 商品增量标识vo vo.productCode必填
     * @return 商品索引Vo集合
     */
    public List<ProductIdxVo> getSearchIndices(List<ProductIdxIdentityVo> identityVos) {
        if (CollectionUtils.isEmpty(identityVos)) {
            return Lists.newArrayList();
        }
        List<ProductIdxIdentityVo> vos = Lists.newArrayList();
        for (ProductIdxIdentityVo vo : identityVos) {
            if (vo.getProductType() == VendorType.TYPE_B.getValue()) {
                vos.add(vo);
            }
        }

        List<ProductIdxVo> idxVos = Lists.newArrayList();
        for (ProductIdxIdentityVo vo : vos) {
            idxVos.add(this.getSearchIdx(vo));
        }

        return idxVos;
    }

    public ProductIdxRespVo getProductIndices(ProductIdxReqVo reqVo) {
        //获取所有商品编码
        List<String> allProductCodes = productRedisDao.getTypeProductCodes(VendorType.valueOf(reqVo.getProductType()));
        List<ProductPrototype> productPrototypes = this.multiBuilder(allProductCodes)
                .buildStocks(reqVo.getDepotCode())
                .buildPrices(reqVo.getDepotCode())
                .build();
        List<ProductIdxVo> productIdxVos = productPrototypes.stream().map(productPrototype -> productPrototype.toProductIdx(reqVo.getDepotCode())).collect(Collectors.toList());
        ProductIdxRespVo respVo = new ProductIdxRespVo();
        respVo.setDepotCode(reqVo.getDepotCode());
        respVo.setProductType(reqVo.getProductType());
        respVo.setIndices(productIdxVos);
        return respVo;
    }
}
